/**
**************************************************************************************
*Palisma - Secrets of the Illuminati is an open-source 2D RPG                        *
*Copyright (C) 2006, Tony Sparks                                                     *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
#pragma once
#include "iconsole.h"
#include "IGameState.h"
#include "input/inputbuffer.h"
#include "log.h"
#include <map>
#include <vector>

// cmd stack size
#define CMD_STACK 20


/**
==============================
An ICommand is an interface for
a function to be executed by the console
==============================
*/
class ICommand 
{
public:
    virtual void Exec( std::string &s ) =0;
};

/**
===============================
Cmds is a holder for all the functions allowed
===============================
*/
class Cmds 
{
public:
    Cmds(void) { cmdlist_f.Set( this ); AddCommand( &cmdlist_f, "cmdlist" ); };

    /** Get a Console command */
    ICommand* GetCommand( const std::string &s) { 
		if( cmdList.find(s) != cmdList.end() )
			return cmdList[s];
		else return NULL;
	};
    /** Add a command */
    void AddCommand( ICommand* cmd,  const std::string &s) { cmdList[s] = cmd; };

    /** Remove a command */
    void RemoveCommand( const std::string &s) { 
        std::map< std::string, ICommand* >::iterator it = cmdList.find(s);
        cmdList.erase( it );     
    };

    /** Get all commands */
    std::map< std::string, ICommand* >& GetAllCommands() { return cmdList; };

private:
    typedef std::map< std::string, ICommand* > type_CmdList;
    type_CmdList cmdList;

    /** Cmd list command */
    class CmdList_f : public ICommand
    {
    public:
        CmdList_f() {};
        void Set(Cmds *cmd) { m_cmd = cmd; };
        void Exec(std::string &s);
        ~CmdList_f() {};
        // retrieve all the command names
        Cmds *m_cmd;
    }; CmdList_f  cmdlist_f;

public:
    virtual ~Cmds(void) {
        RemoveCommand( "cmdlist" );
        std::map< std::string, ICommand* >::iterator it = cmdList.begin();
        for(; it != cmdList.end(); it++)
        {
            // delete all the contents;
            if ( it->second )
            {
                delete it->second;
            }
        }
    };
};

/** Short cuts */
typedef std::map< std::string, ICommand* > _Commands;


/** Console display properties */
struct console_t
{
    // display setting
    float m_fraction;
    // display line
    float m_display;
    // if the console window is moving
    bool  m_moving;

    // print stack
    std::list<std::string> m_printStack;
};

/**
================================
The console allows for running commands and scripts.  
It allows for debugging and setting runtime variables
================================
*/
class Console : public IConsole, public IGameState
{
public:
    Console(void);
    int Init();
	int Start();
	/** Update the console */
    void Update(float dt);
    void Shutdown();
	void Exit();
	/** Deprecated */
    void GetInput();
	/** Get the current Buffer */
    InputBuffer* GetBuffer();
    
    /** Deal with logging */
    void SetLog(bool b) { m_log = b; };
    bool IsLogging() { return m_log; };

    /** IConsole interface */
    void Print( const char *s, ...);
    void Exec ( const std::string &s);

    /** Display settings */
    console_t* GetDisplay() { return &m_cons; };
    void Toggle();
    bool IsShowing() { return m_open; }

	/** Add a command */
	void AddCommand( ICommand *cmd,  const std::string &s); 
	/** Remove a command */
	void RemoveCommand( const std::string &s);

private:
    // auto complete a command
    void AutoComplete(std::string &s );
    // input buffer
    InputBuffer                m_buffer;
    // commands
    Cmds                       m_commands;
    // command stack - for scrolling through old
    // commands
    std::vector< std::string > cmdStack;
    int                        m_currentCmd;

    // Display for scrolling
    console_t                   m_cons;
    // Wethere the console has been initialized
    bool                        m_inited;
    bool                        m_open;

    // Loggin system
    bool                        m_log;
    Log                         m_logger;

public:
    virtual ~Console(void);

};


